/*
 * Copyright 2018-2021 guerlab.net and other contributors.
 *
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.guerlab.smart.pay.service.service.impl;

import lombok.extern.slf4j.Slf4j;
import net.guerlab.commons.number.NumberHelper;
import net.guerlab.smart.pay.core.PayConstant;
import net.guerlab.smart.pay.core.enums.PayStatus;
import net.guerlab.smart.pay.core.exception.*;
import net.guerlab.smart.pay.core.searchparams.PayOrderSearchParams;
import net.guerlab.smart.pay.service.entity.PayOrder;
import net.guerlab.smart.pay.service.mapper.PayOrderMapper;
import net.guerlab.smart.pay.service.properties.PayProperties;
import net.guerlab.smart.pay.service.service.PayOrderService;
import net.guerlab.smart.platform.server.service.BaseServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 支付订单服务实现
 *
 * @author guer
 */
@Slf4j
@Service
public class PayOrderServiceImpl extends BaseServiceImpl<PayOrder, Long, PayOrderMapper, PayOrderSearchParams>
        implements PayOrderService {

    private PayProperties payProperties;

    @Override
    public void markException(Long id, String exceptionReason) {
        exceptionReason = StringUtils.trimToNull(exceptionReason);
        if (NumberHelper.greaterZero(id) && exceptionReason != null) {
            getBaseMapper().markException(id, exceptionReason);
        }
    }

    @Override
    public void removeExceptionMark(Long id) {
        getBaseMapper().removeExceptionMark(id);
    }

    @Override
    protected void insertBefore(PayOrder entity) {
        String orderTitle = StringUtils.trimToNull(entity.getOrderTitle());
        String businessGroup = StringUtils.trimToNull(entity.getBusinessGroup());
        String businessId = StringUtils.trimToNull(entity.getBusinessId());
        BigDecimal amount = entity.getAmount();

        if (orderTitle == null) {
            throw new OrderTitleInvalidException();
        }
        if (orderTitle.length() > PayConstant.ORDER_TITLE_MAX_LENGTH) {
            throw new OrderTitleLengthErrorException();
        }
        if (businessGroup == null) {
            throw new BusinessGroupInvalidException();
        }
        if (businessGroup.length() > PayConstant.BUSINESS_GROUP_MAX_LENGTH) {
            throw new BusinessGroupLengthErrorException();
        }
        if (businessId == null) {
            throw new BusinessIdInvalidException();
        }
        if (businessId.length() > PayConstant.BUSINESS_ID_MAX_LENGTH) {
            throw new BusinessIdLengthErrorException();
        }

        if (!NumberHelper.greaterOrEqualZero(amount)) {
            throw new PayAmountInvalidException();
        }

        PayOrderSearchParams searchParams = new PayOrderSearchParams();
        searchParams.setBusinessGroup(businessGroup);
        searchParams.setBusinessId(businessId);

        if (selectCount(searchParams) > 0) {
            throw new PayOrderBusinessUniqueTagRepeatException();
        }

        boolean payed = !NumberHelper.greaterZero(amount);

        LocalDateTime now = LocalDateTime.now();
        entity.setPayOrderId(sequence.nextId());
        entity.setOrderTitle(orderTitle);
        entity.setBusinessGroup(businessGroup);
        entity.setBusinessId(businessId);
        entity.setCreateTime(now);
        entity.setPayTimeoutTime(now.plusMinutes(payProperties.getTimeoutMinute()));
        entity.setPayCancelTime(null);
        entity.setExceptionFlag(false);
        entity.setExceptionReason(null);

        if (payed) {
            entity.setPayedTime(now);
            entity.setPayStatus(PayStatus.PAYED);
            entity.setPayedSucceedChannel("NONE");
        } else {
            entity.setPayedTime(null);
            entity.setPayStatus(PayStatus.WAIT_PAY);
            entity.setPayedSucceedChannel(null);
        }
    }

    @Autowired
    public void setPayProperties(PayProperties payProperties) {
        this.payProperties = payProperties;
    }
}
